package com.wolf.etl.core;

import com.wolf.etl.core.dialect.AbstractDialect;
import com.wolf.etl.enumeration.DB_TYPE;
import com.wolf.etl.model.EtlFunctionModel;
import com.wolf.etl.model.EtlTableModel;
import com.wolf.etl.model.EtlTableRelModel;
import com.wolf.etl.model.EtlTableRelRuleModel;
import com.wolf.etl.vo.BuildSqlParam;
import com.wolf.etl.vo.Column;
import com.wolf.etl.vo.Database;
import com.wolf.etl.vo.Table;
import com.wolf.exception.ETL_ERROR_MSG;
import com.wolf.exception.WolfException;
import com.wolf.util.DateUtil;
import com.wolf.util.StringUtils;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;

/**
 * 判断字段关联是否合法
 * 表a的N次转换 = 表b的M次转换
 * 简化函数返回类型：字符串 数字 日期
 *
 * @author sdyang
 * @date 2019/11/5 16:37
 **/
@Service("JoinManager")
public class JoinManager {

    private static Logger logger = LoggerFactory.getLogger(JoinManager.class);

    private static final String logger_prefix = "wolf-etl#com.wolf.etl.core#JoinManager";

    private ETLManager etlManager;

    private Database database;

    private BuildSqlParam param;

    private List<Set<String>> typeMap;

    public static JoinManager getInstance(ETLManager etlManager, BuildSqlParam param) {
        JoinManager joinManager = new JoinManager();
        joinManager.etlManager = etlManager;
        joinManager.param = param;
        return joinManager;
    }


    public void check(AbstractDialect dialect, EtlTableRelModel tableRel) {

        // 自定义字段类型匹配
        typeMap = dialect.getColumnTypes();

        database = etlManager.getDataBaseInstance(dialect.getDatasourceId());

        dialect.getCustomFunction(database.getSchema());

        EtlTableModel masterTable = param.getRelMap().get(tableRel.getMaster_table_id());

        EtlTableModel joinTable = param.getRelMap().get(tableRel.getSlave_table_id());

        Table mtable = database.getTable(masterTable.getName());

        Table jtable = database.getTable(joinTable.getName());

        String masterColumnType = mtable.getColumn(tableRel.getMaster_column()).getColumnType();
        String joinColumnType = jtable.getColumn(tableRel.getSlave_column()).getColumnType();

        // 主字段
        List<EtlTableRelRuleModel> rules = param.getMasterTableRelRuleMap().get(tableRel.getId());
        if (rules != null) {
            for (EtlTableRelRuleModel rule : rules) {
                masterColumnType = getReturnType(mtable, rule);
            }
        }

        // 从字段
        rules = param.getSlaveTableRelRuleMap().get(tableRel.getId());
        if (rules != null) {
            for (EtlTableRelRuleModel rule : rules) {
                joinColumnType = getReturnType(jtable, rule);
            }
        }

        // 判断字段类型是否匹配
        if (!check(masterColumnType,joinColumnType)) {
            WolfException.report(ETL_ERROR_MSG.ERROR_TRANSFORM_RULE_004, "表关联字段类型不一致");
        }

    }

    private boolean check(String srcType, String targetType) {
        if (srcType.equalsIgnoreCase(targetType)) {
            return true;
        }

        for (Set<String> s : typeMap) {
            if (s.contains(srcType.toLowerCase()) && s.contains(targetType.toLowerCase())) {
                return true;
            }
        }
        return false;

    }

    /**
     * 检查参数个数和参数类型
     *
     * @param table
     * @param rule
     * @return
     */
    public String getReturnType(Table table, EtlTableRelRuleModel rule) {

        if (rule.isIs_custom()) {
            //自定义函数

        } else {

            // 系统自带函数
            EtlFunctionModel function = etlManager.findFunctionById(rule.getFunction_id());

            // 判断参数个数，检查参数类型
            int count = 0;
            if (StringUtils.isNotEmpty(rule.getParam1())) {
                checkType(table, function.getParam_type_1(), rule.getParam1());
                count++;
            }
            if (StringUtils.isNotEmpty(rule.getParam2())) {
                checkType(table, function.getParam_type_2(), rule.getParam2());
                count++;
            }
            if (StringUtils.isNotEmpty(rule.getParam3())) {
                checkType(table, function.getParam_type_3(), rule.getParam3());
                count++;
            }
            if (StringUtils.isNotEmpty(rule.getParam4())) {
                checkType(table, function.getParam_type_4(), rule.getParam4());
                count++;
            }

            if (count != function.getParam_num()) {
                WolfException.report(ETL_ERROR_MSG.ERROR_TRANSFORM_RULE_002, "函数参数个数不匹配");
            }


            return function.getReturn_type();
        }
        return "";

    }

    /**
     * 检查关联类型是否匹配
     *
     * @param table
     * @param functionType
     * @param column
     */
    private void checkType(Table table, String functionType, String column) {

        String columnType = null;

        // 判断是否列名
        if (column.contains("[COLUMN]")) {
            // 列类型
            String columnName = getColumnName(column);
            Column column1 = table.getColumn(columnName);
            columnType = column1.getColumnType();
        } else if (column.contains("[RULE_ID]")) {
            // 函数返回值
            columnType = getFunctonReturnType(column);
        } else {
            // 值类型
            columnType = getType(column);
        }

        // 判断数据类型
        if (!check(columnType,functionType)) {
            WolfException.report(ETL_ERROR_MSG.ERROR_TRANSFORM_RULE_002, "函数参数类型不匹配");
        }
    }

    /**
     * @param cloumn
     * @param rules
     * @return
     */
    public String renderByRules(String cloumn, List<EtlTableRelRuleModel> rules) {

        String result = cloumn;

        if (CollectionUtils.isEmpty(rules)) {
            return result;
        }

        for (EtlTableRelRuleModel rule : rules) {
            EtlFunctionModel function = etlManager.findFunctionById(rule.getFunction_id());
            String alias = param.getAliasMap().get(rule.getTable_id());
            String param1 = getRenderValue(alias, rule.getParam1(), result);
            String param2 = getRenderValue(alias, rule.getParam2(), result);
            String param3 = getRenderValue(alias, rule.getParam3(), result);
            String param4 = getRenderValue(alias, rule.getParam4(), result);
            result = String.format(function.getFunction_format(), param1, param2, param3, param4);
        }
        return result;
    }

    private String getRenderValue(String alias, String cloumn, String result) {
        if (StringUtils.isEmpty(cloumn)) {
            return "";
        }

        if (cloumn.contains("[RULE_ID]")) {
            return result;
        }
        if (cloumn.contains("COLUMN")) {
            String columnName = cloumn.substring(cloumn.indexOf("[COLUMN]${") + 10, cloumn.length() - 1);
            return String.format("%s.%s", alias, columnName);
        }
        return cloumn;
    }

    /**
     * 函数返回类型
     * [FUNCTION_ID]${函数id}
     *
     * @param str
     * @return
     */
    private String getFunctonReturnType(String str) {
        String rule_id = str.substring(str.indexOf("[RULE_ID]${") + 11, str.length() - 1);
        if (StringUtils.isEmpty(rule_id)) {
            WolfException.report(ETL_ERROR_MSG.ERROR_TRANSFORM_RULE_002, "函数参数有误");
        }
        EtlTableRelRuleModel rule = etlManager.findTableRelRuleById(Long.parseLong(rule_id));
        if (rule == null) {
            WolfException.report(ETL_ERROR_MSG.ERROR_TRANSFORM_RULE_002, "函数参数有误");
        }

        if (rule.isIs_custom()) {
            return "";
        } else {
            EtlFunctionModel function = etlManager.findFunctionById(rule.getFunction_id());
            if (function == null) {
                WolfException.report(ETL_ERROR_MSG.ERROR_TRANSFORM_RULE_003, String.format("找不到函数id=%s", rule.getFunction_id()));
            }
            return function.getReturn_type();
        }
    }

    /**
     * 格式：[COLUMN]${列名}
     *
     * @param str
     * @return
     */
    private String getColumnName(String str) {
        String columnName = str.substring(str.indexOf("[COLUMN]${") + 10, str.length() - 1);
        return columnName;
    }

    // 将字段类型转换为简单类型：字符串 数字 日期
    private String getSimpleType(int type) {
        DB_TYPE dbType = DB_TYPE.valueOf(type);
        if (dbType.isNumberType()) {
            return "number";
        }
        if (dbType.isDateType()) {
            return "date";
        }
        return "string";
    }

    private String getType(String str) {
        if (StringUtils.isNumeric(str)) {
            return "integer";
        }
        if (StringUtils.isDateType(str, DateUtil.YYYY_MM_DD_HH_MM_SS)) {
            return "date";
        }
        return "char";
    }

}
